package upm.pb4agent.team8.Common;

import java.io.FileInputStream;
import java.security.spec.MGF1ParameterSpec;
import java.util.ArrayList;
import java.util.Collections;
import java.util.Iterator;
import java.util.LinkedHashMap;
import java.util.List;
import java.util.Map;
import java.util.Properties;
import java.util.ResourceBundle;

import javax.crypto.spec.PBEParameterSpec;

import jade.content.Concept;
import jade.content.ContentElement;
import jade.content.abs.AbsContentElement;
import jade.content.lang.Codec;
import jade.content.lang.sl.SLCodec;
import jade.content.onto.Ontology;
import jade.content.onto.basic.Action;
import jade.core.AID;
import jade.core.Agent;
import jade.domain.DFService;
import jade.domain.FIPAAgentManagement.DFAgentDescription;
import jade.domain.FIPAAgentManagement.ServiceDescription;
import jade.lang.acl.ACLMessage;
import jade.wrapper.AgentContainer;
import jade.wrapper.AgentController;
import upm.pb4agent.common.Constant;
import upm.pb4agent.ontology.PB4AgentOntology;

public class PB4Utils
{
	public static enum MsgTypes
	{
		Low,
		Standard
	}
	
	public static final Codec codec = new SLCodec();
	public static final Ontology ontology = PB4AgentOntology.getInstance(); 
	public static final  VirtualConsole Console = new VirtualConsole();
	public static final PB4Properties PropertyReader = new PB4Properties();
	
	private static boolean TrySendMessage( int performative, Agent senderAgent, AID receiver, ContentElement content, String MsgContent )
	{
		ACLMessage aclMessage = new ACLMessage(performative);
		aclMessage.addReceiver(receiver);
		aclMessage.setLanguage(PB4Utils.codec.getName());
		aclMessage.setOntology(PB4Utils.ontology.getName());	
		aclMessage.setProtocol(MsgContent);
		try 
		{
			senderAgent.getContentManager().fillContent(aclMessage, content);
			senderAgent.send(aclMessage);
			Console.WriteLine("Message \"" + MsgContent +"\" from "+ senderAgent.getName() + " to " + receiver.getName() + " was sent.", MsgTypes.Low );
		}
		catch (Exception e)
		{
			Console.WriteLine( "Error trying to send the Message :\"" + MsgContent + "\"", e);
			return false;
		}
		
		return true;
	}
	
	public static boolean TrySendConceptMessage( int performative, Agent senderAgent, AID receiver,Concept concept )
	{
		boolean success =false;
		Action action = new Action(senderAgent.getAID(), concept);
		success = PB4Utils.TrySendMessage(performative, senderAgent, receiver, action, concept.getClass().getSimpleName());
		return success;
	}
	
	public static boolean TrySendMessage( int performative, Agent senderAgent, AID receiver,String content )
	{
		ACLMessage aclMessage = new ACLMessage(performative);
		aclMessage.addReceiver(receiver);

		try 
		{
			aclMessage.setContent(content);
			senderAgent.send(aclMessage);
			Console.WriteLine("Message from "+ senderAgent.getName() + " to " + receiver.getName() + " was sent.", MsgTypes.Low );
		}
		catch (Exception e)
		{
			Console.WriteLine( "Error trying to send the Message "+ e);
			return false;
		}
		
		return true;
	}
	
	public static AID TryCreateAgent(Agent creatorAgent, String className, String nick, Object[] args)
	{
		AgentContainer agentContainer = creatorAgent.getContainerController();
		try
		{
			AgentController agentController = agentContainer.createNewAgent(nick, className,args);
			PB4Utils.Console.WriteLine("Calling constructor "+ nick + " Agent", MsgTypes.Low);
			agentController.start();				
			return new AID(nick, AID.ISLOCALNAME);
		}
		catch (Exception e)
		{
			PB4Utils.Console.WriteLine("Error calling constructor "+ nick + " Agent" , e);
			return null;
		}

	}
	public static AID TryFindAgent( Agent searcherAgent, String type)
	{
		DFAgentDescription dfAgentDescription = PB4Utils.TryCreateAgentFindDescription(type);
		AID agent= null;
		try
		{	
			DFAgentDescription[] resultDescriptors = DFService.search(searcherAgent, dfAgentDescription);
			if (resultDescriptors.length == 1)
			{
				agent = (AID) resultDescriptors[0].getName();
				Console.WriteLine("Agent found : " +type, MsgTypes.Low);
			}
			else
			{
				Console.WriteLine(searcherAgent.getName() + "can not find Agent : " + type + ","+ resultDescriptors[0].getName() );
			}
		}
		catch (Exception e)
		{
			//Console.WriteLine("Error Trying to find Agent : " + type, e);
		}
		return agent;
	}
	
	public static boolean TryRegisterAgent(Agent agent, String type)
	{
		DFAgentDescription dfAgentDescription = PB4Utils.TryCreateAgentRegisterDescription(agent.getName(), type);
		try
		{
			DFService.register(agent, dfAgentDescription);
			Console.WriteLine("Agent " + type + " registered succesfully.", MsgTypes.Low);
			return true;
		}
		catch (Exception e)
		{
			Console.WriteLine("Error Trying to register Agent : " + type, e);
			return false;
		}
	}
	
	public static DFAgentDescription TryCreateAgentRegisterDescription( String name, String type)
	{
		DFAgentDescription dfAgentDescription = new DFAgentDescription();
		ServiceDescription serviceDescription = new ServiceDescription();
		serviceDescription.setType(type);
		serviceDescription.setName(name);
		dfAgentDescription.addServices(serviceDescription);
		
		return dfAgentDescription;
	}
	
	public static DFAgentDescription TryCreateAgentFindDescription( String type)
	{
		DFAgentDescription dfAgentDescription = new DFAgentDescription();
		ServiceDescription serviceDescription = new ServiceDescription();
		serviceDescription.setType(type);
		dfAgentDescription.addServices(serviceDescription);
		
		return dfAgentDescription;
	}

	public static ContentElement GetMessageContent( Agent agent, ACLMessage msg)
	{
		ContentElement content = null;
		
		try 
		{
			content = agent.getContentManager().extractContent(msg);
		} 
		catch (Exception e)
		{
			PB4Utils.Console.WriteLine("Error reading content from " + agent.getName(), e);
		}
		
		return content; 
	}

	public static Map<String, Float> SortHashMap(Map<String, Float> passedMap)
	{
	    List<String> mapKeys = new ArrayList<String>(passedMap.keySet());
	    List<Float> mapValues = new ArrayList<Float>(passedMap.values());
	    Collections.sort(mapValues);
	    Collections.sort(mapKeys);
	    Collections.reverse(mapValues);
	    
	    LinkedHashMap<String,Float> sortedMap = 
	        new LinkedHashMap<String,Float>();
	    
	    Iterator<Float> valueIt = mapValues.iterator();
	    while (valueIt.hasNext()) {
	        Object val = valueIt.next();
	        Iterator<String> keyIt = mapKeys.iterator();
	        
	        while (keyIt.hasNext()) {
	            Object key = keyIt.next();
	            String comp1 = passedMap.get(key).toString();
	            String comp2 = val.toString();
	            
	            if (comp1.equals(comp2)){
	                passedMap.remove(key);
	                mapKeys.remove(key);
	                sortedMap.put((String)key, (Float)val);
	                break;
	            }

	        }

	    }
	    return sortedMap;
	}
}
